package com.yj.core.config.redis;

import com.alibaba.fastjson.parser.ParserConfig;
import com.alibaba.fastjson.support.spring.FastJsonRedisSerializer;
import com.google.common.base.Splitter;
import com.google.common.collect.Sets;
import com.yj.core.exception.ServiceException;
import lombok.extern.slf4j.Slf4j;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.redisson.config.SentinelServersConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisSentinelConfiguration;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.jedis.JedisClientConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.*;
import org.springframework.data.redis.serializer.*;
import org.springframework.util.CollectionUtils;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.JedisSentinelPool;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;


/**
 * redis配置
 *
 * @author yxp
 * @date 19-03-13
 */
@Configuration
@ConditionalOnProperty(prefix = "redis", value = "use")
@Slf4j
public class RedisConfig {

    @Autowired
    private ConfigurableApplicationContext ctx;

    @Bean
    public RedisConnectionFactory redisConnectionFactory() {
        ConfigurableEnvironment ctxEnvironment = ctx.getEnvironment();

        log.info("开始注册Redis");

        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        jedisPoolConfig.setMaxIdle(Integer.valueOf(ctxEnvironment.getProperty("redis.pool.maxIdle")));
        jedisPoolConfig.setMaxWaitMillis(Long.valueOf(ctxEnvironment.getProperty("redis.pool.maxWait")));
        jedisPoolConfig.setMaxTotal(Integer.valueOf(ctxEnvironment.getProperty("redis.pool.maxActive")));
        jedisPoolConfig.setTestOnBorrow(Boolean.valueOf(ctxEnvironment.getProperty("redis.pool.testOnBorrow")));

        String nodeStr = ctxEnvironment.getProperty("redis.sentinel.nodes");
        RedisSentinelConfiguration redisSentinelConfiguration;

        Set<String> nodeList = new HashSet<>(Splitter.on(",").splitToList(nodeStr));

        if (CollectionUtils.isEmpty(nodeList)){
            throw new ServiceException("未配置redis节点");
        }

        JedisConnectionFactory jedisConnectionFactory;
        if (nodeList.size() > 1){
            redisSentinelConfiguration = new RedisSentinelConfiguration("mymaster", nodeList);

            jedisConnectionFactory = new JedisConnectionFactory(redisSentinelConfiguration, jedisPoolConfig);
            jedisConnectionFactory.afterPropertiesSet();
            return jedisConnectionFactory;
        } else {
            List<String> nodeList2 = new ArrayList<>(Splitter.on(",").splitToList(nodeStr));
            String host = nodeList2.get(0).split(":")[0];
            String port = nodeList2.get(0).split(":")[1];
            RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration(host, Integer.valueOf(port));

            jedisConnectionFactory = new JedisConnectionFactory(redisStandaloneConfiguration);
        }

        log.info("注册Redis完毕");
        return jedisConnectionFactory;
    }

    @Bean
    public RedisSerializer fastJsonRedisSerializer() {
        return new FastJsonRedisSerializer<>(Object.class);
    }


    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory,
                                                       RedisSerializer fastJsonRedisSerializer) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);

        /**
         * 全局开启AutoType，不建议使用
         * ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
         * 建议使用这种方式，小范围指定白名单
         */
        ParserConfig.getGlobalInstance().addAccept("cn.swifthealth.");

        // 设置值（value）的序列化采用FastJsonRedisSerializer。
        redisTemplate.setValueSerializer(fastJsonRedisSerializer);
        redisTemplate.setHashValueSerializer(fastJsonRedisSerializer);
        // 设置键（key）的序列化采用StringRedisSerializer。
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());

        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }

    @Bean
    public RedissonClient redissonClient(){
        ConfigurableEnvironment ctxEnvironment = ctx.getEnvironment();
        String nodeStr = ctxEnvironment.getProperty("redis.sentinel.nodes");

        List<String> nodeList = new ArrayList<>(Splitter.on(",").splitToList(nodeStr));

        if (CollectionUtils.isEmpty(nodeList)){
            throw new ServiceException("未配置redis节点");
        }

        Config config = new Config();

        if (nodeList.size() > 1){
            SentinelServersConfig sentinelServersConfig = config.useSentinelServers()
                    .setMasterName("mymaster")
                    .setScanInterval(2000)
                    .setTimeout(6000)
                    .setRetryAttempts(5)
                    .setKeepAlive(true)
                    .setPingConnectionInterval(30000);
            for (String node : nodeList){
                sentinelServersConfig.addSentinelAddress("redis://" + node);
            }
        }else {
            //Set<String> sentinels = Sets.newHashSet();
            //sentinels.add(nodeList.get(0));
            //JedisSentinelPool sentinelPool = new JedisSentinelPool("mymaster", sentinels);

            config.useSingleServer()
                    .setAddress("redis://" + nodeList.get(0).split(":")[0] + ":" + nodeList.get(0).split(":")[1])
                    .setKeepAlive(true)
                    .setPingConnectionInterval(30000);
        }

        return Redisson.create(config);


    }
}
